﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Windows.Media.Media3D10
{
    /// <summary>
    /// Représente une rotation 3D en utilisant les coordonnées sphériques
    /// </summary>
    public sealed class SphericalRotation3D10 : Rotation3D10
    {
        #region Dependency Properties
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="Yaw"/>.
        /// </summary>
        public static readonly DependencyProperty YawProperty =
            DependencyProperty.Register("Yaw", typeof(float), typeof(SphericalRotation3D10),
            new PropertyMetadata(0.0f, new PropertyChangedCallback(Yaw_PropertyChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="Pitch"/>.
        /// </summary>
        public static readonly DependencyProperty PitchProperty =
            DependencyProperty.Register("Pitch", typeof(float), typeof(SphericalRotation3D10),
            new PropertyMetadata(0.0f, new PropertyChangedCallback(Pitch_PropertyChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="Roll"/>.
        /// </summary>
        public static readonly DependencyProperty RollProperty =
            DependencyProperty.Register("Roll", typeof(float), typeof(SphericalRotation3D10),
            new PropertyMetadata(0.0f, new PropertyChangedCallback(Roll_PropertyChanged)));
        #endregion
        
        #region DependencyProperties Callbacks
        private static void Yaw_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ((SphericalRotation3D10)sender).OnYawChanged(e);
        }
        
        private static void Pitch_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ((SphericalRotation3D10)sender).OnPitchChanged(e);
        }
        
        private static void Roll_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ((SphericalRotation3D10)sender).OnRollChanged(e);
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="SphericalRotation3D10"/>. 
        /// </summary>
        public SphericalRotation3D10()
        {
            ComputeValue();
        }

        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="SphericalRotation3D10"/> avec des valeurs de rotation
        /// </summary>
        /// <param name="yaw">Cap</param>
        /// <param name="pitch">Tangage</param>
        /// <param name="roll">Roulis</param>
        public SphericalRotation3D10(float yaw, float pitch, float roll)
        {
            this.Yaw = yaw;
            this.Pitch = pitch;
            this.Roll = roll;
            ComputeValue();
        }
        #endregion

        #region Data
        private SlimDX.Matrix _value;
        #endregion

        #region Public Properties
        /// <summary>
        /// Obtient ou définit le Cap de la rotation
        /// </summary>
        public float Yaw
        { 
            get { return (float)GetValue(YawProperty); }
            set { SetValue(YawProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit le Tangage de la rotation
        /// </summary>
        public float Pitch
        { 
            get { return (float)GetValue(PitchProperty); }
            set { SetValue(PitchProperty, value); }
        }

        /// <summary>
        /// Obtient ou définit le Roulis de la rotation
        /// </summary>
        public float Roll
        { 
            get { return (float)GetValue(RollProperty); }
            set { SetValue(RollProperty, value); }
        }
        #endregion

        #region Private Members
        private void OnYawChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ComputeValue();
        }

        private void OnPitchChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ComputeValue();
        }

        private void OnRollChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ComputeValue();
        }

        private void ComputeValue()
        {
            Console.WriteLine(this.Roll.ToRadians());
            this._value = SlimDX.Matrix.RotationYawPitchRoll(this.Yaw.ToRadians(), this.Pitch.ToRadians(), this.Roll.ToRadians());
        }
        #endregion

        #region Rotation3D10 Implementation
        /// <summary>
        /// Représentation matricielle de la transformation
        /// </summary>
        protected internal override SlimDX.Matrix Value
        {
            get { return _value; }
        }
        #endregion

        #region Freezable Implementation
        /// <summary>
        /// Une fois implémentée dans une classe dérivée, initialise une nouvelle instance de la classe dérivée <see cref="Freezable"/>. 
        /// </summary>
        /// <returns>Nouvelle instance.</returns>
        protected override Freezable CreateInstanceCore()
        {
            return new SphericalRotation3D10();
        }
        #endregion
    }
}
